﻿namespace OutLook.Model.Domains
{
    using OutLook.Model.Infrastructure;
    using System;
    using System.Xml.Serialization;
    using System.Runtime.Serialization;

    /// <summary>
    /// Discription substance factors using for modeling
    /// </summary>
    /// Ussualy the model has the form:
    /// S:=(Qs*K*Coefficient)/(1+Qs*K*Coefficient);
    /// [CastIron substance]:=Load substance*(1-S)*Incoming
    /// where Qs determined in model
    /// So, for each substance needs three factors
    [DataContract]
    public class SubstanceFactor : IAssignable, IEquatable<SubstanceFactor>, IValidatable
    {
        #region Constructors

        /// <summary>
        /// Initializes new default instance of SubstanceFactor
        /// </summary>
        public SubstanceFactor() : this(string.Empty, 0.0d, 0.0d, 0.0d) { }

        /// <summary>
        /// Initializes new instance of SubstanceFactor
        /// </summary>
        /// <param name="element">TODO:Nastya</param>
        /// <param name="k">TODO:Nastya</param>
        /// <param name="incoming">TODO:Nastya</param>
        /// <param name="coefficient">TODO:Nastya</param>
        public SubstanceFactor(string element, double k, double incoming, double coefficient)
        {
            Element = element;
            K = k;
            Incoming = incoming;
            Coefficient = coefficient;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Title of substance
        /// </summary>
        [DataMember(Order = 1)]
        public string Element
        {
            get { return m_Element; }
            private set { m_Element = value; }
        }

        /// <summary>
        /// Factor "K" for using in model
        /// </summary>
        [DataMember(Order = 2)]
        public double K
        {
            get { return m_K; }
            set { m_K = value; }
        }

        /// <summary>
        /// Factor "Coefficient" for using in model
        /// </summary>
        [DataMember(Order = 3)]
        public double Coefficient
        {
            get { return m_Coefficient; }
            set { m_Coefficient = value; }
        }

        /// <summary>
        /// Factor "Incoming" for using in model
        /// </summary>
        [DataMember(Order = 4)]
        public double Incoming
        {
            get { return m_Incoming; }
            set { m_Incoming = value; }
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Assigns values of current substance factor to the argument object
        /// </summary>
        /// <param name="obj">Object to assign to</param>
        /// <exception cref="ArgumentNullException">If object to assign to is nullable</exception>
        /// <exception cref="NotSupportedException">If object to assign to doesn't fit</exception>
        public void AssignTo(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException();

            if (obj is SubstanceFactor)
            {
                SubstanceFactor factor = obj as SubstanceFactor;
                factor.Coefficient = m_Coefficient;
                factor.Element = m_Element;
                factor.Incoming = m_Incoming;
                factor.K = m_K;

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region IEquatable<SubstanceFactor> Implementation

        /// <summary>
        /// Compares current SubstanceFactor with another one
        /// </summary>
        /// <param name="other">Another SubstanceFactor</param>
        /// <returns>True - If current SubstanceFactor and another one are equal, otherwise -False</returns>
        public bool Equals(SubstanceFactor other)
        {
            if (other == null)
                return false;

            if (Element.Equals(other.Element) && K == other.K && Coefficient == other.Coefficient && Incoming == other.Incoming)
                return true;

            return false;
        }

        #endregion

        #region IValidatable Implementation

        /// <summary>
        /// Validates Substance Factor
        /// </summary>
        /// <returns>True - if current Substance Factor is valid, otherwise - false</returns>
        public bool Validate()
        {
            ///TODO: Substance Factor VALIDATION
            if (string.IsNullOrWhiteSpace(m_Element) || string.IsNullOrEmpty(m_Element))
                return false;

            return true;
        }

        #endregion

        #region Fields

        private string m_Element = default(string);
        private double m_K = default(double);
        private double m_Coefficient = default(double);
        private double m_Incoming = default(double);

        #endregion
    }
}
